package com.njtoyo.taxi.admin.service.business.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.zhxu.bs.BeanSearcher;
import cn.zhxu.bs.util.MapBuilder;
import cn.zhxu.bs.util.MapUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njtoyo.taxi.admin.cache.PrimaryCachePutter;
import com.njtoyo.taxi.admin.library.Const;
import com.njtoyo.taxi.admin.library.common.GeoPoint;
import com.njtoyo.taxi.admin.library.common.OperationRecordHelper;
import com.njtoyo.taxi.admin.library.common.util.CopyUtil;
import com.njtoyo.taxi.admin.logic.business.TaxisLogic;
import com.njtoyo.taxi.admin.mapper.master.entity.*;
import com.njtoyo.taxi.admin.mapper.master.mapper.*;
import com.njtoyo.taxi.admin.rest.export.taxis.TaxisListData;
import com.njtoyo.taxi.admin.rest.presenter.business.taxis.TaxiPresenter;
import com.njtoyo.taxi.admin.rest.presenter.business.taxis.TaxiQueryActivationCountPresenter;
import com.njtoyo.taxi.admin.rest.presenter.business.taxis.TaxisPresenter;
import com.njtoyo.taxi.admin.rest.presenter.open.taxi.TaxiDeviceVersionPresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserIdentityPresenter;
import com.njtoyo.taxi.admin.rest.readfile.taxis.*;
import com.njtoyo.taxi.admin.rest.wrapper.business.taxis.*;
import com.njtoyo.taxi.admin.rest.wrapper.open.taxi.TaxiVersionWrapper;
import com.njtoyo.taxi.admin.service.business.TaxiService;
import com.njtoyo.taxi.admin.utils.CCBaseEntity;
import com.njtoyo.taxi.admin.utils.SignUtil;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.taxi.entity.common.RestResult;
import com.taxi.entity.common.ResultEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import static cn.hutool.core.util.ObjectUtil.isNotEmpty;
import static java.util.stream.Collectors.toList;

@Component
@DS(Const.PRIMARY_DS)
public class TaxisServiceImpl implements TaxiService {
    @Autowired
    private TaxiMapper taxiMapper;
    @Autowired
    private DriverMapper driverMapper;
    @Autowired
    private TaxisLogic taxisBatchLogic;
    @Autowired
    private PrimaryCachePutter primaryCachePutter;
    @Autowired
    private RideMapper rideMapper;
    @Autowired
    private OperationRecordHelper operationRecordHelper;
    @Autowired
    private GeoCantonMapper geoCantonMapper;
    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private TaxiLastLocateMapper taxiLastLocateMapper;
    @Autowired
    private TaxiOnRideMapper taxiOnRideMapper;
    @Autowired
    private BeanSearcher beanSearcher;
    @Autowired
    private DriverDeviceRelationshipMapper driverDeviceRelationshipMapper;
    @Autowired
    private DriverExtraInformationMapper driverExtraInformationMapper;

    /**
     * 车辆列表
     *
     * @param adminUser
     * @param wrapper
     * @return
     */
    @Override
    public RestResult<Page<TaxisPresenter>> selectListTaxi(AdminUser adminUser, TaxiQueryListWrapper wrapper) {
        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        switch (adminUser.getAccountType()) {
            case canton:
                wrapper.setCantonIds(identity.getCantonIds());
                break;
            case company:
                if (isNotEmpty(wrapper.getCompanyId())) {
                    wrapper.getCompanyId().addAll(identity.getCompanyIds());
                } else {
                    wrapper.setCompanyId(identity.getCompanyIds());
                }
        }
        Page<TaxisPresenter> page = taxiMapper.selectListTaxis(wrapper);
        List<TaxisPresenter> list = page.getRecords();
        List<Long> ids = list.stream().map(TaxisPresenter::getId).collect(toList());
        List<Long> companyids = list.stream().map(TaxisPresenter::getCompanyId).collect(toList());
        //验证是否存在数据
        if (ids.size() == 0) {
            return RestResult.success(page);
        }
        //公司信息
        List<Company> companyList = companyMapper.selectList(Wrappers.<Company>lambdaQuery().in(Company::getId, companyids));
        Map<Long, String> geoCantonsMap = null;
        if (isNotEmpty(companyList)) {
            List<Long> cantonids = companyList.stream().map(Company::getCantonId).collect(toList());
            //行政区信息
            QueryWrapper<GeoCanton> geoCantonQueryWrapper = new QueryWrapper<>();
            geoCantonQueryWrapper.select("id", "name");
            geoCantonQueryWrapper.in("id", cantonids);
            List<Map<String, Object>> maps = geoCantonMapper.selectMaps(geoCantonQueryWrapper);
            geoCantonsMap = maps.stream().collect(Collectors.toMap(i -> Long.valueOf(i.get("id").toString()), i -> i.get("name").toString()));
        }
        //司机信息
        QueryWrapper<Driver> driverQueryWrapper = new QueryWrapper<>();
        driverQueryWrapper.in("taxi_id", ids);
        List<Driver> drivers = driverMapper.selectList(driverQueryWrapper);
        Map<Long, List<Driver>> driverMap = drivers.stream().collect(Collectors.groupingBy(Driver::getTaxiId));

        for (TaxisPresenter result : list) {
            companyList.stream().filter(company -> result.getCompanyId().equals(company.getId())).forEach(company -> {
                result.setCompanyName(company.getName());
                result.setCantonId(company.getCantonId());
            });
            result.setCantonName(geoCantonsMap.getOrDefault(result.getCantonId(), null));
            result.setDrivers(driverMap.getOrDefault(result.getId(), new ArrayList<>()));
            if (StrUtil.isNotBlank(result.getGpsTime())) {
                result.setGpsTime(DateUtil.date(Long.valueOf(result.getGpsTime())).toString());
            }
            if (CollUtil.isNotEmpty(result.getDrivers())) {
                List<Long> driverIds = result.getDrivers().stream().map(Driver::getId).collect(toList());
                DriverDeviceRelationship driverDeviceRelationship = driverDeviceRelationshipMapper.selectOne(Wrappers.<DriverDeviceRelationship>lambdaQuery().eq(DriverDeviceRelationship::getState, 1).in(DriverDeviceRelationship::getDriverId, driverIds).orderByDesc(DriverDeviceRelationship::getUpdatedAt).last("limit 1"));
                if (ObjectUtil.isNotNull(driverDeviceRelationship)) {
                    result.setLoginTime(driverDeviceRelationship.getUpdatedAt());
                }
                List<DriverExtraInformation> driverExtraInformations = driverExtraInformationMapper.selectList(Wrappers.<DriverExtraInformation>lambdaQuery()
                        .in(DriverExtraInformation::getDriverId, driverIds)
                        .orderByDesc(DriverExtraInformation::getUpdatedAt));
                if(CollUtil.isEmpty(driverExtraInformations)){
                    continue;
                }
                DriverExtraInformation extraInformation = driverExtraInformations.get(0);
                if (ObjectUtil.isNotNull(extraInformation) && StrUtil.isNotBlank(extraInformation.getDeviceAutoInfo())) {
                    JSONObject jsonObject = JSON.parseObject(extraInformation.getDeviceAutoInfo());
                    result.setVersion(jsonObject.getString("v"));
                }
            }
        }
        return RestResult.success(page);
    }


    /**
     * 注册车辆
     *
     * @param wrapper
     * @return
     */
    @Override
    public RestResult register(TaxiRegisterWrapper wrapper) {
        String serialNumber = wrapper.getSerialNumber();
        String plateNumber = wrapper.getPlateNumber();
        Long companyId = wrapper.getCompanyId();
        try {
            Taxi register = taxisBatchLogic.registerBatch(plateNumber, serialNumber, companyId);

            taxiLastLocateMapper.insert(new TaxiLastLocate().setTaxiId(register.getId()).setCreatedAt(DateUtil.date()).setPoint(new GeoPoint(new Double(0.0), new Double(0.0))));
            return RestResult.success(register);
        } catch (Exception e) {
            return RestResult.failed(e.getMessage());
        }
    }


    /**
     * 上传Excel批量注册车辆
     *
     * @param file
     * @param wrapper
     * @return
     */
    @Override
    public RestResult<RegisterBatchResult> registerBatch(MultipartFile file, RegisterBatchWrapper wrapper) throws IOException {
        RegisterBatchListener listener = new RegisterBatchListener(taxisBatchLogic, wrapper);
        EasyExcel.read(file.getInputStream(), RegisterBatchData.class, listener).sheet().doRead();
        return RestResult.success(listener.getResult());

    }

    /**
     * 修改车辆
     *
     * @param id
     * @param wrapper
     * @return
     */
    @Override
    public RestResult updateTaxi(Long id, TaxiUpdateWrapper wrapper) {
        Taxi taxi = taxiMapper.selectById(id);
        if (ObjectUtils.isEmpty(taxi)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        String plateNumber = wrapper.getPlateNumber();
        Integer count = taxiMapper.selectPlateNumber(plateNumber);
        if (count >= 1) {
            if (!plateNumber.equals(taxi.getPlateNumber())) {
                return RestResult.failed("车牌号对应车辆已存在");
            }
        }
        new LambdaUpdateChainWrapper<>(taxiMapper).eq(Taxi::getId, id).
                set(Taxi::getCompanyId, wrapper.getCompanyId()).
                set(Taxi::getPlateNumber, plateNumber).
                set(Taxi::getSerialNumber, wrapper.getSerialNumber()).
                set(Taxi::getUpdatedAt, new Date()).
                update();
        List<Long> longs = driverMapper.selectDriverByIds(id);
        //清除掉绑定该车辆的司机缓存
        for (Long l : longs) {
            primaryCachePutter.deleteDriverCacheById(l);
        }
        operationRecordHelper.addBusinessLog(
                String.format("修改了车辆 [%d] 的信息车牌号由%s -> %s,公司id由%s -> %s,发动机号由%s -> %s",
                        id, taxi.getPlateNumber(), wrapper.getPlateNumber(), taxi.getCompanyId(), wrapper.getCompanyId(), taxi.getSerialNumber(), wrapper.getSerialNumber()));
        return RestResult.success();
    }

    /**
     * 报废车辆,以及设置车辆可用
     *
     * @param id
     * @param wrapper
     * @return
     */
    @Override
    public RestResult updateTaxisScrap(Long id, TaxiScrapWrapper wrapper) {
        Boolean isScrapped = wrapper.getIsScrapped();
        try {
            taxisBatchLogic.scrapBatch(id, isScrapped);
        } catch (Exception e) {
            return RestResult.failed(e.getMessage());
        }
        return RestResult.success();
    }

    /**
     * 删除车辆
     *
     * @param id
     * @return
     */

    @Override
    public RestResult deleteTaxi(Long id) {
        Taxi taxi = taxiMapper.selectById(id);
        if (ObjectUtils.isEmpty(taxi)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        List<Long> longs = driverMapper.selectDriverByIds(id);
        if (!ObjectUtils.isEmpty(longs)) {
            return RestResult.failed("该车辆绑定了司机");
        }
        Integer count = rideMapper.selectRideCount(id);
        if (count > 0) {
            return RestResult.failed("该车辆存在行程");
        }
        taxiMapper.deleteById(id);
        operationRecordHelper.addBusinessLog(String.format("删除了车辆 [%d] 的信息", id));
        return RestResult.success();
    }

    /**
     * 批量报废车辆
     *
     * @param file
     * @return
     * @throws IOException
     */
    @Override
    public RestResult<ScrapBatcResult> scrapBatch(MultipartFile file) throws IOException {
        ScrapBatchListener listener = new ScrapBatchListener(taxisBatchLogic);
        EasyExcel.read(file.getInputStream(), ScrapBatchData.class, listener).sheet().doRead();
        return RestResult.success(listener.getResult());
    }


    /**
     * 车牌查询所有车辆
     *
     * @param plateNumber
     * @return
     */
    @Override
    public RestResult<List<TaxiPresenter>> taxisListByPlateNumber(String plateNumber) {
        QueryWrapper<Taxi> wrapper = new QueryWrapper<>();
        wrapper.select("id", "plate_number", "serial_number", "company_id", "is_scrapped");
        wrapper.eq("plate_number", plateNumber);
        List<Taxi> taxilist = taxiMapper.selectList(wrapper);

        if (ObjectUtils.isEmpty(taxilist)) {
            return RestResult.failed("车辆不存在");
        }
        List<TaxiPresenter> taxiPresenter = BeanUtil.copyToList(taxilist, TaxiPresenter.class);
        Company company = companyMapper.selectById(taxilist.get(0).getCompanyId());
        taxiPresenter.get(0).setCompanyName(company.getName());
        return RestResult.success(taxiPresenter);
    }

    /**
     * 车辆的导出
     *
     * @param wrapper
     * @param response
     * @return
     * @throws IOException
     */
    @Override
    public void TaxisBatchexport(TaxiExportWrapper wrapper, HttpServletResponse response) throws IOException {
        List<TaxisListData> list = taxiMapper.selectTaxisList(wrapper);
        List<Long> contonIds = list.stream().map(TaxisListData::getCantonId).collect(toList());
        if (!ObjectUtils.isEmpty(contonIds)) {
            //行政区ID
            QueryWrapper<GeoCanton> geoCantonQueryWrapper = new QueryWrapper<>();
            geoCantonQueryWrapper.select("id", "name");
            geoCantonQueryWrapper.in("id", contonIds);
            List<GeoCanton> geoCantons = geoCantonMapper.selectList(geoCantonQueryWrapper);
            for (TaxisListData t : list) {
                Long cantonId = t.getCantonId();
                for (GeoCanton g : geoCantons) {
                    if (cantonId.equals(g.getId())) {
                        t.setCantonName(g.getName());
                    }
                }
            }
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (TaxisListData t : list) {
            String lastLocateTimestamp = t.getLastLocateTimestamp();
            if (lastLocateTimestamp != null) {
                long l = Long.parseLong(lastLocateTimestamp);
                String format = sdf.format(l);
                t.setLastLocateTimestamp(format);
            }
        }
        String fileName = URLEncoder.encode("车辆信息导出", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), TaxisListData.class).sheet(0).doWrite(list);
    }

    @Override
    public RestResult<TaxiQueryActivationCountPresenter> getActivationCount(AdminUser adminUser, QueryTaxiActivationCountWrapper wrapper) {
        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        switch (adminUser.getAccountType()) {
            case canton:
                wrapper.setCantonIds(identity.getCantonIds());
                break;
            case company:
                if (ObjectUtil.isNotEmpty(wrapper.getCompanyIds())) {
                    wrapper.getCompanyIds().addAll(identity.getCompanyIds());
                } else {
                    wrapper.setCompanyIds(identity.getCompanyIds());
                }
                break;
        }

        TaxiQueryActivationCountPresenter res = new TaxiQueryActivationCountPresenter();
        res.setActivationCount(taxiMapper.getActivationCount(wrapper));

        return RestResult.success(res);
    }

    @Override
    public RestResult sendOrder(Long taxiId) {
        taxiOnRideMapper.delete(Wrappers.<TaxiOnRide>lambdaQuery().eq(TaxiOnRide::getTaxiId, taxiId));
        return RestResult.success();
    }

    @Override
    public RestResult getNearbyCarByPoint(String lng, String lat, String callMode) {

        List<Dict> taxis = taxiMapper.getNearbyCarByPoint(new GeoPoint(Convert.toDouble(lng), Convert.toDouble(lat)), callMode);

        return RestResult.success(taxis);
    }

    @Override
    public RestResult getTaxiDeviceVersion(TaxiVersionWrapper taxiVersionWrapper) {
        if (StrUtil.isEmpty(taxiVersionWrapper.getPlateNumber())) return RestResult.build(ResultEnum.PARAMS_ERROR);
        Taxi taxi = taxiMapper.selectTaxiByPlateNumber(taxiVersionWrapper.getPlateNumber());
        if (Objects.isNull(taxi)) return RestResult.build(ResultEnum.NOT_FOUND);
        Map<String, Object> params = MapUtils.builder().field(TaxiDeviceVersionPresenter::getTaxiId, taxi.getId()).build();
        List<TaxiDeviceVersionPresenter> taxiDeviceVersionPresenterList = beanSearcher.searchList(TaxiDeviceVersionPresenter.class, params);
        return RestResult.success(taxiDeviceVersionPresenterList);
    }

    @Override
    public RestResult bindCC(Long id) {
        String client_id = "a75b6f61e454ddff";
        String sign_key = "b7f84614f3f3118960092c58a8a50bdc";

        Taxi taxi = taxiMapper.selectById(id);
        if (ObjectUtil.isNull(taxi)) {
            return RestResult.failed("绑定失败,车辆不存在");
        } else if (taxi.getIsScrapped()) {
            return RestResult.failed("绑定失败,车辆已报废");
        }

        CCBaseEntity baseEntity = new CCBaseEntity();
        baseEntity.setTimestamp(DateUtil.current());
        baseEntity.setClient_id(client_id);
        baseEntity.setCarNum(taxi.getPlateNumber());
        baseEntity.setDeviceId(taxi.getId().toString());
        baseEntity.setSign(SignUtil.genSign(baseEntity, sign_key));
        String body = HttpRequest.post("https://taxi-online.njydi.cn/yd-front-service/common/carBind").body(JSON.toJSONString(baseEntity)).execute().body();
        JSONObject json = JSON.parseObject(body);
        Console.log("绑定曹操返回结果:{}",  json.toJSONString());
        //2025年05月12日15:27:43 返回结果{"msg":"操作成功","code":200}
        if (json.getInteger("code") == 200) {
            return RestResult.success("绑定成功");
        } else {
            return RestResult.failed("绑定失败");
        }

    }
}
